import { Injectable } from "@angular/core";
import { Observable, of as ObservableOf, BehaviorSubject } from "rxjs";
import { catchError, map } from "rxjs/operators";
import { FetchService } from "../net/fetch.service";
import { UtilService } from "../util/util.service";
import * as _ from 'lodash';
import * as queryString from "querystring";

@Injectable()
export class AuthService {
    storage: Storage = localStorage;
    menuDataChanged = new BehaviorSubject<Array<MenuItemModel>>(
        JSON.parse(localStorage.getItem("menuList"))
    );
    activeTopMenuChanged = new BehaviorSubject<MenuItemModel>(
        JSON.parse(localStorage.getItem("activeTopMenu"))
    );
    private baseUrl = (window as any).environment.apiBaseUrl;
    constructor(
        private fetchService: FetchService,
        private utilService: UtilService
    ) {}

    login(account: string, password: string): Observable<boolean> {
        return this.fetchService
            .post<LoginResponseModel>(
                "login",
                { account, password },
                { showNotify: false }
            )
            .pipe(
                map(response => {
                    const wrsMenuList = response.menuList;
                    _.remove(wrsMenuList, item => {
                        return item.href === '/map';
                    });
                    this.updateMenuData(wrsMenuList);
                    const mapMenu = [
                        {
                            accessible: "6",
                            href: "/map",
                            icon: "map",
                            id: "f3225e41-dae5-4de8-9018-125cf6696461",
                            name: "一张图",
                            parentId: "0",
                            parentIds: "0",
                            sort: 0,
                            subnodeCnt: 0,
                            type: "2",
                        }
                    ];
                    this.updateSysMenuList('mapMenuList', mapMenu);
                    this.updateSysMenuList('wsMenuList', wrsMenuList);
                    this.updateSysMenuList('gateMenuList', response.gateMenuList);
                    this.updateSysMenuList('sfMenuList', response.nxSfList);
                    this.updateSysMenuList('pmMenuList', response.nxProjectList);
                    this.updateUserProfile(response.token, response.userInfo);
                    this.updateRoleInfo(response.roleList[0]);
                    return true;
                }),
                catchError(error => {
                    return this.handleError(error);
                })
            );
    }

    casLogin(account: string): Observable<boolean> {
        return this.fetchService
            .post<LoginResponseModel>(
                `${this.baseUrl}verify`,
                { account },
                { showNotify: false }
            )
            .pipe(
                map(response => {
                    const wrsMenuList = response.menuList;
                    _.remove(wrsMenuList, item => {
                        return item.href === '/map';
                    });
                    this.updateMenuData(wrsMenuList);
                    const mapMenu = [
                        {
                            accessible: "6",
                            href: "/map",
                            icon: "map",
                            id: "f3225e41-dae5-4de8-9018-125cf6696461",
                            name: "一张图",
                            parentId: "0",
                            parentIds: "0",
                            sort: 0,
                            subnodeCnt: 0,
                            type: "2",
                        }
                    ];
                    this.updateSysMenuList('mapMenuList', mapMenu);
                    this.updateSysMenuList('wsMenuList', wrsMenuList);
                    this.updateSysMenuList('gateMenuList', response.gateMenuList);
                    this.updateSysMenuList('sfMenuList', response.nxSfList);
                    this.updateSysMenuList('pmMenuList', response.nxProjectList);
                    this.updateUserProfile(response.token, response.userInfo);
                    this.updateRoleInfo(response.roleList[0]);
                    return true;
                }),
                catchError(error => {
                    return this.handleError(error);
                })
            );
    }
    logout(): void {
        this.setToken(null);
        this.setUserProfile(null);
        this.setRoleInfo(null);
        this.updateActiveTopMenu(null);
    }

    getUserProfile(): UserProfileModel {
        const profile = this.storage.getItem("userInfo");
        return profile
            ? JSON.parse(localStorage.getItem("userInfo"))
            : undefined;
    }

    getUserName(): string {
        return this.getUserProfile() && this.getUserProfile().name;
    }

    getUserImage(): string {
        return this.getUserProfile() && this.getUserProfile().image;
    }

    getToken(): string {
        return this.storage.getItem("token");
    }

    isLoggedIn(): boolean {
        return !!this.getUserProfile() && !!this.getToken();
    }

    private setToken(token: string): void {
        if (token) {
            this.storage.setItem("token", token);
        } else {
            this.storage.removeItem("token");
        }
    }

    private setUserProfile(profile: UserProfileModel): void {
        if (profile) {
            this.storage.setItem("userInfo", JSON.stringify(profile));
        } else {
            this.storage.removeItem("userInfo");
        }
    }
    private setRoleInfo(roleInfo): void {
        if (roleInfo) {
            this.storage.setItem("roleInfo", JSON.stringify(roleInfo));
        } else {
            this.storage.removeItem("roleInfo");
        }
    }

    private updateUserProfile(
        token: string,
        profileObject: UserProfileModel
    ): void {
        this.setToken(token);
        this.setUserProfile(profileObject);
    }
    private updateRoleInfo(roleObject): void {
        this.setRoleInfo(roleObject);
    }
    private handleError(error: any): Observable<boolean> {
        console.error(error);
        this.updateUserProfile(undefined, undefined);
        return ObservableOf(false);
    }

    updateMenuData(menuList: Array<MenuItemModel>): void {
        if (!menuList) {
            localStorage.removeItem("menuList");
            this.menuDataChanged.next(undefined);
        }
        const menuStr = JSON.stringify(menuList);
        if (menuStr !== localStorage.getItem("menuList")) {
            menuList.sort((a, b) => {
                return a.sort - b.sort;
            });
            localStorage.setItem("menuList", JSON.stringify(menuList));
            this.menuDataChanged.next(menuList);
        }
    }

    updateSysMenuList(name: string, menuList: Array<MenuItemModel>): void {
        if (!menuList) {
            localStorage.removeItem(name);
        }
        const menuStr = JSON.stringify(menuList);
        if (menuStr !== localStorage.getItem(name)) {
            localStorage.setItem(name, JSON.stringify(menuList));
        }
    }
    updateActiveTopMenu(activeTopMenu: MenuItemModel): void {
        if (!activeTopMenu) {
            localStorage.removeItem("activeTopMenu");
            this.activeTopMenuChanged.next(undefined);
        }
        const menuItemStr = JSON.stringify(activeTopMenu);
        if (menuItemStr !== localStorage.getItem("activeTopMenu")) {
            localStorage.setItem("activeTopMenu", menuItemStr);
            this.activeTopMenuChanged.next(activeTopMenu);
        }
    }

    getTopMenu(menu?: Array<MenuItemModel>): Observable<Array<MenuItemModel>> {
        const menuValue = menu ? menu : this.menuDataChanged.getValue();
        const topMenu = menuValue.filter(item => item.type !== "3");
        // console.log(topMenu);
        topMenu.map(item => {
            item.children = [];
            menuValue.map(submenu => {
                if (submenu.type == '3' && submenu.subnodeCnt > 0) {
                    submenu.children = menuValue.filter(m => m.parentId == submenu.id);
                }
                if (submenu.parentId == item.id) {
                    item.children.push(submenu);
                }
            });
        });
        return ObservableOf(topMenu);
    }

    getTopMenuItems(
        menu?: Array<MenuItemModel>
    ): Observable<Array<MenuItemModel>> {
        const menuValue = menu ? menu : this.menuDataChanged.getValue();
        return ObservableOf(
            menuValue.filter(item => /*item.accessible && */ item.type !== "3")
        );
    }

    getSubMenuData(
        id: string,
        menu?: Array<MenuItemModel>
    ): Observable<MenuItemModel> {
        const menuValue = menu ? menu : this.menuDataChanged.getValue();
        // menu = this.menuDataChanged.getValue().filter(item => item.accessible);
        return this.utilService.flat2Nested(menuValue, {
            pathProperty: "parentIds",
            rootId: id
        });
    }

    getSearch(): any {
        const search = location.href.split('?')[1] || '';
        return queryString.parse(search);
    }
}

export interface LoginResponseModel {
    token: string;
    menuList: Array<MenuItemModel>;
    gateMenuList: Array<MenuItemModel>;
    nxSfList: Array<MenuItemModel>;
    nxProjectList: Array<MenuItemModel>;
    roleList: Array<object>;
    userInfo: UserProfileModel;
}

export interface UserProfileModel {
    id: string;
    account: string;
    name: string;
    image: string;
    phone: string;
    [key: string]: any;
}

export interface MenuItemModel {
    id: string;
    name: string;
    type: string; // 1: flat top menu; 2: icon top menu; 3: side menu
    accessible?: any; // 当前用户是否具有菜单访问权限
    subnodeCnt: number; // 子节点数量
    parentId: string; // 上级菜单节点id，顶级菜单父节点为"0"
    parentIds: string; // ","分割的菜单id path
    level?: number; // 菜单级别
    sort: number; // 菜单排序
    href?: string; // 菜单指向路由地址
    icon?: string;
    tooltip?: string;
    expanded?: boolean;
    children?: Array<MenuItemModel>;
    [key: string]: any;
}
